`include "common.svh"
module frontend #(
    parameter FRONTEND_WIDTH = 2
) (
    input clk,
    input rst,
    // Redirect Req by backend
    input i_redirect_valid,
    input i_redirect_replay,
    input word_t i_redirect_pc,
    input i_redirect_bpu_res_valid,
    input BPU_Res i_redirect_bpu_res,
    // IRAM Req
    input o_iram_ready,
    output o_iram_valid,
    output IRAM_Req o_iram_req,
    // IRAM Rsp
    input IRAM_Rsp i_iram_rsp,
    // IBUF
    output o_ibuf_valid,
    input o_ibuf_ready,
    output o_ibuf_entry_valid[FRONTEND_WIDTH-1:0],
    output IBUF_Entry o_ibuf_entry[FRONTEND_WIDTH-1:0],
    //for performace
    output ibuf_full,
    output ibuf_empty
);
  localparam BPU_AW = $clog2(FRONTEND_WIDTH);

  word_t bpu_i_pc;
  logic bpu_i_valid;
  logic bpu_i_ready;
  BPU_Res bpu_o_res;
  logic bpu_o_valid;
  logic bpu_o_res_valid;
  logic [BPU_AW-1:0] bpu_o_res_offset;
  logic bpu_o_res_multi_branch;

  logic fetch_o_ibuf_valid;
  logic fetch_o_ibuf_ready;
  logic fetch_o_ibuf_entry_valid[FRONTEND_WIDTH-1:0];
  IBUF_Entry fetch_o_ibuf_entry[FRONTEND_WIDTH-1:0];

  bpu #(BPU_AW) inst_bpu (
      .update_valid(i_redirect_bpu_res_valid),
      .update_pc(i_redirect_pc),
      .update_res(i_redirect_bpu_res),
      .i_valid(bpu_i_valid),
      .i_ready(bpu_i_ready),
      .i_pc(bpu_i_pc),
      .o_valid(bpu_o_valid),
      .o_res_valid(bpu_o_res_valid),
      .o_res(bpu_o_res),
      .o_res_offset(bpu_o_res_offset),
      .o_res_multi_branch(bpu_o_res_multi_branch),
      .*
  );

  fetch #(FRONTEND_WIDTH) inst_fetch (
      .i_redirect_target(i_redirect_replay ? i_redirect_pc : i_redirect_bpu_res.target),
      .o_bpu_pc(bpu_i_pc),
      .o_bpu_valid(bpu_i_valid),
      .o_bpu_ready(bpu_i_ready),
      .i_bpu_res(bpu_o_res),
      .i_bpu_valid(bpu_o_valid),
      .i_bpu_res_valid(bpu_o_res_valid),
      .i_bpu_res_offset(bpu_o_res_offset),
      .i_bpu_res_multi_branch(bpu_o_res_multi_branch),
      .o_ibuf_valid(fetch_o_ibuf_valid),
      .o_ibuf_ready(fetch_o_ibuf_ready),
      .o_ibuf_entry_valid(fetch_o_ibuf_entry_valid),
      .o_ibuf_entry(fetch_o_ibuf_entry),
      .*
  );
`ifdef HAS_IBUF

  localparam IBUF_ENTRY_SIZE = $size(IBUF_Entry);
  multi_fifo #(IBUF_ENTRY_SIZE, `IBUF_AW, BPU_AW) ibuf (
      .almost_full(ibuf_full),
      .empty(ibuf_empty),
      .flush(i_redirect_valid),
      .i_valid(fetch_o_ibuf_valid),
      .i_ready(fetch_o_ibuf_ready),
      .i_data_valid(fetch_o_ibuf_entry_valid),
      .i_data(fetch_o_ibuf_entry),
      .o_valid(o_ibuf_valid),
      .o_ready(o_ibuf_ready),
      .o_data_valid(o_ibuf_entry_valid),
      .o_data_ready(o_ibuf_entry_valid),
      .o_data(o_ibuf_entry),
      .*
  );

`else

  assign o_ibuf_valid = fetch_o_ibuf_valid;
  assign fetch_o_ibuf_ready = o_ibuf_ready;
  assign o_ibuf_entry_valid = fetch_o_ibuf_entry_valid;
  assign o_ibuf_entry = fetch_o_ibuf_entry;
  assign ibuf_full = 1'b0;
  assign ibuf_empty = 1'b0;

`endif  //HAS_IBUF


  // always_ff@(posedge clk) begin
  //   if(!rst) begin
  //     if(i_redirect_valid) begin
  //       $display("Redirect 0x%08x",i_redirect_pc);
  //     end
  //   end
  // end
endmodule
